/**
**********************************************************************
* @file     signal_link_list.h
* @brief    单向链表的头文件
* @details
* 定义了单向链表相关的数据类型，并且定义了对单向链表进行操作的宏，
* 声明了对单向链表进行操作的函数的原型。
* 使用的时候，导入本头文件即可得到对单向链表进行操作的所有信息。
* @author   CaiJing
* @date     2021-05-11 09:02:36
* @copyright Copyright &copy; 2021 wy1107412334@163.com All rights reserved
* @version  v0.0.7
*
* \n Email:  wy1107412334@163.com
* \n Blog:   None
* \n Github: https://github.com/wy1107412334
* \n Gitee:  https://gitee.com/git.git1107412334.com
*
**********************************************************************
* @note
* None.
**********************************************************************
* @attention
* None.
**********************************************************************
@verbatim
@endverbatim
**********************************************************************
* @par 历史记录
*  1. V0.0.1: caijing，2021-05-11 09:02:36
*    - 首次编写
*  2. V0.0.2: jcai, 2021年5月17日 13点46分
*    - 新增函数原型和修复宏定义错误
*    - 删除行末多余空白字符
*  3. V0.0.3: jcai, 2021年5月19日 19点07分
*    - 修改寻找链表中指定节点的函数及其回调函数的参数表
*  4. V0.0.4: jcai, 2021年5月31日 13点32分
*    - 定义枚举值用于函数的错误码
*    - 定义遍历链表的宏
*  5. V0.0.5: jcai, 2021年6月29日 02点01分
*    - 新增销毁链表的函数原型
*    - 修复宏问题
*  6. V0.06: jcai, 2021年7月9日 11点15分
*    - 修改doxygen的简要注释的格式
*    - 给宏加上注释
*    - 链表头新增一个长度字段
*  7. v0.0.7: jcai, 2021年8月3日 10点24分
*    - 完善doxygen注释格式
*
*<center>Copyright &copy; 2021 wy1107412334@163.com All rights reserved</center>
**********************************************************************
*/

#ifndef __SIGNAL_LINK_LIST_H__
#define __SIGNAL_LINK_LIST_H__


/* 头文件导入区 ----------------------------------------------------*/

#include <stdint.h>
#include <stdio.h>


#ifdef __cplusplus
extern "C"
{
#endif

/** @addtogroup SIGNAL_LINK_LIST
 * @{
 */


/** @defgroup SIGNAL_LINK_LIST_CompilationDefines signal link list compilation defines
 * @brief 条件编译定义
 * @{
 */



/** defgroup SIGNAL_LINK_LIST_CompilationDefines
 * @}
 */


/** @defgroup SIGNAL_LINK_LIST_Input_Interface signal link list Input API Interface
 * @brief 模块输入API接口。即对外部少量依赖模块的API接口
 * @{
 */



/** defgroup SIGNAL_LINK_LIST_Input_Interface
 * @}
 */


/** @defgroup SIGNAL_LINK_LIST_Exported_MacroDefines signal link list exported macro defines
 * @brief 全局宏定义
 * @{
 */

/** @def SLLIST_INIT(sl)
 * 链表初始化
 *
 * @param [out] sl: 指向链表头的指针
 */
#define SLLIST_INIT(sl) (sl)->head=NULL, (sl)->tail=NULL, (sl)->length = 0

/** @def DEFINE_SLLIST(name)
 * 定义链表并初始化
 *
 * @param name: 链表变量名
 */
#define DEFINE_SLLIST(name) SL_LIST name = {0}

/** @def SL_FIRST_NODE(psl)
 * 获取链表第一个节点的地址
 *
 * @param [in] psl: 指向链表头的指针
 * @return 链表头节点的地址
 */
#define SL_FIRST_NODE(psl)  (psl)->head
/** @def SL_NEXT_NODE(pnode)
 * 获取链表下一个节点的地址
 *
 * @param [in] pnode: 指向链表中节点的指针
 * @return 下一个节点的地址
 */
#define SL_NEXT_NODE(pnode) (pnode)->next
/** @def SL_LAST_NODE(psl)
 * 获取链表最后一个节点的地址
 *
 * @param [in] psl: 指向链表头的指针
 * @return 链表尾节点的地址
 */
#define SL_LAST_NODE(psl)   (psl)->tail
/** @def SL_FOREACH(node, list)
 * 链表遍历
 *
 * @param [in,out] node: SL_NODE类型的指针变量，
 *                       用于依次指向链表 list 中的每个节点
 * @param [in] list: 指向链表头的指针
 */
#define SL_FOREACH(node, list) \
    for (node = (list)->head; node; node = node->next)

/** defgroup SIGNAL_LINK_LIST_Exported_MacroDefines
 * @}
 */


/** @defgroup SIGNAL_LINK_LIST_Exported_Types signal link list exported types
 * @brief 全局数据类型声明
 * @{
 */

/** @enum sl_err
 * 链表返回的负值错误码及其含义
 */
enum sl_err {
    SL_ERR_ARGS     = -1,   /*!< 输入参数有误 */
    SL_ERR_NOTEMPTY = -2,   /*!< 链表非空 */
    SL_ERR_ISEXIST  = -3,   /*!< 节点存在链表中 */
    SL_ERR_NOTEXIST = -4,   /*!< 节点不存在链表中 */
    SL_ERR_INDEX    = -5,   /*!< 节点索引超出链表范围 */
    SL_ERR_ISEMPTY  = -6,   /*!< 链表为空 */
};

/** @struct sl_node
 * 链表节点
 *
 * 保存下一个节点的地址
 */
typedef struct sl_node {
    struct sl_node    *next;    /*!< 指向下一个节点的指针 */
} SL_NODE;                      /*!< 结构体 struct sl_node 的别名 */

/** @struct SL_LIST
 * 链表表头
 *
 * 链表表头中保存了链表的头节点和尾节点地址。
 * 通过本数据结构可以完整描述一个链表。
 */
typedef struct {
    SL_NODE     *head;          /*!< 指向链表头节点的指针 */
    SL_NODE     *tail;          /*!< 指向链表尾节点的指针 */
    uint32_t     length;        /*!< 链表中节点的数量，即链表长度 */
} SL_LIST;

/**
 * 用于遍历链表的回调函数的原型
 *
 * 本函数一般用于获取/打印节点 node 中的值的。
 *
 * @param [in] node: 指向链表中的一个节点
 */
typedef void (*sl_trav_callback)(const SL_NODE *node);

/**
 * 用于获取链表中指定节点的地址的回调函数的原型
 *
 * 本函数一般用于想要获取存在某个数据的节点的地址。
 *
 * @param [in] node: 指向链表中的一个节点的指针
 * @param [in] arg: 用户传入的参数
 * @return 如果节点 node 是想寻找的节点，则返回非0值；否则返回0
 * @note 不建议在此函数中修改 node 指向的节点的数据
 */
typedef int (*sl_match_callback)(const SL_NODE *node, void *arg);

/**
 * 用于指定链表排序方式的回调函数的原型
 *
 * 如果如果此函数按照节点 pNode1 中某个值小于 pNode2 中某个值，
 * 并且返回非0值的方式进行处理的话，那么链表中的节点将按照从小到大的顺序排列；
 *
 * 如果如果此函数按照节点 pNode1 中某个值大于 pNode2 中某个值，
 * 并且返回非0值的方式进行处理的话，那么链表中的节点将按照从大到小的顺序排列；
 *
 * @param [in] pNode1: 指向链表中的一个节点
 * @param [in] pNode2: 指向链表中的一个节点
 * @return 返回非0值，则将交换节点 pNode1 和节点 pNode2 的位置。
 *         返回0值，则不交换
 */
typedef int (*sl_sort_callback)(const SL_NODE *pNode1, const SL_NODE *pNode2);


/** defgroup SIGNAL_LINK_LIST_Exported_Types
 * @}
 */






/**********************************************************************
                全局变量声明
**********************************************************************/







/**********************************************************************
                全局函数声明
**********************************************************************/


/**
 * @brief    静态链表头初始化
 * @details  本函数用于将 sl 指向的的链表置为空链表。
 * @param[out]  sl: 指向要初始化的链表头。
 * @retval  none
 * @note 如果 sl 指向的链表为非空链表，那么在执行本函数后，链表中节点就丢失了
 * @warning  sl 不能为 NULL
 * @see sllist_alloc_init()
 */
static inline void sllist_static_init(SL_LIST *sl)
{
    SLLIST_INIT(sl);
}


extern SL_LIST *sllist_alloc_init(void);
extern int      sllist_free(const SL_LIST *sl);
extern void     sllist_destroy(SL_LIST *sl);
extern int32_t  sllist_destroyCallback(SL_LIST *sl, sl_trav_callback callback);
extern int32_t  sllist_isempty(const SL_LIST *sl);
extern uint32_t sllist_length(const SL_LIST *sl);
extern int32_t  sllist_insert_head(SL_LIST *sl, SL_NODE *node);
extern int32_t  sllist_insert_tail(SL_LIST *sl, SL_NODE *node);
extern int32_t  sllist_insert_at(SL_LIST *sl, SL_NODE *node, uint32_t index);
extern int32_t  sllist_addr2at(SL_LIST *sl, SL_NODE *node);
extern SL_NODE *sllist_at(const SL_LIST *sl, uint32_t index);
extern SL_NODE *sllist_find(const SL_LIST *sl, sl_match_callback callback,
                            void *arg);
extern int32_t  sllist_delete(SL_LIST *sl, const SL_NODE *node);
extern SL_NODE *sllist_deleteAt(SL_LIST *sl, uint32_t index);
extern void     sllist_traverse(SL_LIST *sl, sl_trav_callback callback);
extern void     sllist_sort(SL_LIST *sl, sl_sort_callback callback);
extern int32_t  sllist_inversion(SL_LIST *sl);







/** addtogroup SIGNAL_LINK_LIST
 * @}
 */

#ifdef __cplusplus
}
#endif
#endif // __SIGNAL_LINK_LIST_H__


/**   Copyright (C) 2021 wy1107412334@163.com All rights reserved  **/
/***************************** END OF FILE **************************/

